package org.NooLab.itexx.app.controller;


import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;


import org.NooLab.itexx.ITexxWindowCommons;
import org.NooLab.itexx.ITexxWindowIntf;
import org.NooLab.itexx.app.controller.analyzer.SerDocumentScoring;
import org.NooLab.itexx.app.controller.results.SearchEngineResultItem;
import org.NooLab.itexx.app.controller.results.SearchEngineResults;
import org.NooLab.itexx.stuctures.RequestHistory;
import org.NooLab.utilities.datatypes.IndexedDistances;
import org.NooLab.utilities.logging.PrintLog;
import org.jdesktop.application.SessionStorage;




public class SessionManager implements SessionManagerIntf{

	ITexxWindowIntf app;
	ITexxWindowCommons appCommons;
	ItexxModelController modelController;
	
	SessionStorage storage;
	RequestHistory requestHistory;
	
	/** finally completed and ranked items, ready for being displayed */
	private SearchEngineResults globalSearchEngineResults;
	/** buffer list  */
	SearchEngineResults seCompletedResultsItemsBuffer;
	ScoredSerDocuments scoredSerDocuments;
	
	SearchEngineResultsImporter importer ; // == Observer !!! for PageLoader
	
	boolean rankingUpdateReleased=false;
	boolean serScoringIsRunning = false ;
	SerScoring serScoring; 
	boolean collScoringIsRunning = false ;
	CollScoring collScoring;
	boolean processCompletistIsRunning = false;
	
	int statusFlag;
	protected String lastPackageGuidAnnounced;

	PrintLog out = new PrintLog(2,true);
	ArrayList<String> excludedDomains;
	// ========================================================================
	public SessionManager(ITexxWindowIntf app) {
		// 
		this.app = app ;
		
		appCommons = app.getAppCommons();
		modelController = appCommons.getModelController();
		
		// out = appCommons.out ;
		out.setPrefix("[ITEXX-SMGR]");
		// the data
		requestHistory = new RequestHistory();
		
		setGlobalSearchEngineResults(new SearchEngineResults( appCommons ));
		seCompletedResultsItemsBuffer = new SearchEngineResults(appCommons) ;
	
		scoredSerDocuments = new ScoredSerDocuments(this);
		// FoundResultsGuiUpdater
		// the tools
		
		importer = new SearchEngineResultsImporter(this);  
		serScoring = new SerScoring(this) ;
		
		collScoring = new CollScoring(this) ;
		
		excludedDomains = appCommons.getAppProperties().getIniPreferences().getExcludedDomains() ;
		
		out.setPrefix("[iTexx-Gui]") ;
	}
	// ========================================================================
	
	public void close(){
		serScoringIsRunning = false;
		collScoringIsRunning = false ;
		
		processCompletistIsRunning=false;
		
		scoredSerDocuments.close() ;
	}
	
	/**
	 * this is requested by "openPanelSource()" in class "ItexxModelController"
	 */
	public String getSourceForPhysicalPanel(int physPanelIndex) {
		//
		String srcUrl="";
		
		try{
		

			if (modelController==null){
				modelController = appCommons.getModelController();
			}
			IndexedDistances panelMap = modelController.getPanelMap() ;
			int n=panelMap.size();
			
			int index = panelMap.getItem(physPanelIndex).getIndex2() ;
			
			ScoredSerDocument serDoc = scoredSerDocuments.getItems().get(index);
			
			srcUrl = serDoc.getDocUrl() ;
			
		}catch(Exception e){
			srcUrl = "-";
		}
		
		return srcUrl;
	}

	public RequestHistory getHistory() {
		// 
		return requestHistory;
	}

	public RequestHistory getRequestHistory() {
		return requestHistory;
	}

	public ScoredSerDocuments getScoredSerDocuments() {
		return scoredSerDocuments;
	}

	public void setRequestHistory(RequestHistory requestHistory) {
		this.requestHistory = requestHistory;
	}

	public ITexxWindowIntf getApp() {
		return app;
	}

	public SessionStorage getStorage() {
		return storage;
	}
	
	public void publishPreparedSearchEngineResults( SearchEngineResults seResults) {

		// Adding the new results to global list
		
		// sorting it
		
		// setting the update trigger for the GUI (hosed by commons)
	}

	
	/*
	 			// loading of pages and calculating the rank values is organized by Session manager !!! ??? 
			// determineRanking( searchEngineResults );
			
			// now storing to files, preparing the snips for the Found-page 
			// and adding the snips to the global list
			// this list will be worked on by the object FoundResultsGuiUpdater (running a queue digester for that list)
			// which updates the Found-page 
			if (r==0){
				// put the items to the global list
				// (which should be hosted by a database !!!
				// it contains all items for the current session
				// hence this list is part of the SessionManager
				SessionManager smgr = appCommons.getSessionManager() ;
				smgr.publishPreparedSearchEngineResults( searchEngineResults );
				
				FoundResultsGuiUpdater gup; // just for quick dev jumping
			}
	 
	 */
	
	public Observer getObserver(){
		return importer;
	}

	public void setGlobalSearchEngineResults(SearchEngineResults globalSearchEngineResults) {
		this.globalSearchEngineResults = globalSearchEngineResults;
	}

	public SearchEngineResults getGlobalSearchEngineResults() {
		return globalSearchEngineResults;
	}
	public int getStateOnProcess(){
		return statusFlag ;
	}
	public void setStateOnProcess(int typeOfPackage, String guid, int statusFlag) {
		// 
		
		this.statusFlag = statusFlag;
		
		if (statusFlag == SessionManagerIntf._REQUEST_RAID_COMPLETED){
			
			out.print(2, "task completed (2)...");
			
			appCommons.getWindowGui().getMainStatusBar().showBusyIndicator(false);
			// now we can again start the update of the result list
			rankingUpdateReleased = true;
			
			if (appCommons._DIAGNOSIS==1){
				out.delay(2000);
				// appCommons.getModelController().tmp();
			}
			
			// before printing the final list...
			// check whether indeed all processes completed, doing so in a dedicated thread
			new ProcessCompletist();
			
		} 
		
	}

	// ..........................
	class ProcessCompletist implements Runnable{
		
		Thread prcomplThrd;
		
		public ProcessCompletist(){
		
			prcomplThrd = new Thread(this,"prcomplThrd");
			prcomplThrd.start();
		}

		@Override
		public void run() {

			processCompletistIsRunning = true;
			
			int z=0;
			while ((z<400) && (appCommons.getModelController().someProcessesAreAlive())){
				out.delay(50);
				z++;
			}
			
			processCompletistIsRunning = false;
			
			FoundResultsGuiUpdater gups = appCommons.getResultsGuiUpdater();
			gups.prepareFinalList();
			// we also have to save it to a tmp file that could be reloaded (next start, session load)
			// that file is indicated by a session.catalog file (in xml)
			
		}
		
		
	}
	// ..........................
	
	public void announceLastPackageguid(String guid) {
		// TODO Auto-generated method stub
		lastPackageGuidAnnounced = guid;
	}
	
}




/**
 * calc of rank score of documents based on all documents of a (series of ) request, 
 * modifies the global list
 * 
 * it needs a global result list of at least 50 documents;
 *
 */
class CollScoring implements Runnable {
	
	SessionManager parent;
	
	public  CollScoring(SessionManager smgr){
		
		parent = smgr;
		
	}

	@Override
	public void run() {
		// 
		boolean isWorking=false;
		parent.collScoringIsRunning = true;
		int n=0;
		
		while (parent.collScoringIsRunning ){
			
			if (parent.rankingUpdateReleased){
				// fill the queue
				// int n= 123
			
				// is list long enough?
				
				
				// set the indicator back to blocking
				parent.rankingUpdateReleased = false;
			}
			
			if ((isWorking==false) && (n>50) ){
				isWorking=true;
				
				parent.out.delay(20) ;
				
				isWorking=false;
			}
		} // while ->
		
		parent.collScoringIsRunning = false ;
	}
	
	
	
} //  CollScoring 

// calc of rank score of single documents, put it to global list
class SerScoring implements Runnable {

	Thread serscThrd ;
	SessionManager parent;
	
	// ..........................................
	public SerScoring (SessionManager smgr){
		
		parent = smgr;

		serscThrd = new Thread(this,"serscThrd") ;
		serscThrd.start();
	}
	// ..........................................
	
	
	@Override
	public void run() {
		boolean isWorking = false;
		
		parent.out.printErr(2, "... SER scoring process started working...  waiting for incoming SER items") ;
		
		parent.serScoringIsRunning = true; 
		
		while (parent.serScoringIsRunning){
			
			if ((isWorking==false) && (parent.seCompletedResultsItemsBuffer.size()>0)){
				isWorking = true;
				
				SearchEngineResultItem serItem = parent.seCompletedResultsItemsBuffer.get(0) ;
				parent.seCompletedResultsItemsBuffer.getItems().remove(0) ;
				
				// do we know about this website ?
				// boolean hb = checkScoredItemsForUrl( parent.scoredSerDocuments, serItem.getTargetDocUrl());
				//if (hb==false)
				{
					
				
											parent.out.print(2,"...going to score the document <"+serItem.getGuid()+"> retrieved through query " +serItem.getSeQuery());
				    SerDocumentScoring scoring = new SerDocumentScoring(parent.appCommons, parent,serItem);
				    
				    registerScoring(scoring);
				    // scoring = null;
				}
				/*
				 * serItems contain the content of documents; this will be rated in "SerDocumentScoring"
				 * Once the scoring has been completed, a new object will be created, containing WordList and content string;
				 * (for later re-scoring), as well as url
				 * these objects are collected into a further queue as contained in "ScoredSerDocuments"
				 * the class "ScoredSerDocuments" maintains a sub-process ("ListService"), which digests the incomog items
				 */
				
				parent.out.delay(300);
				
				if (parent.appCommons.getModelController().isUserBreak()){
					parent.seCompletedResultsItemsBuffer.getItems().clear();	
				}
				isWorking = false;
				
			}else{
				if (parent.out!=null){
					parent.out.delay(50);
				}
			}
			
		}// ->
		
		parent.serScoringIsRunning = false;
		
		parent.out.printErr(2, "... SER scoring process stopped working.") ;
	}


	private void registerScoring(SerDocumentScoring scoring) {
		
		SearchEngineResultItem serItem ;
		int iPos;
		
											parent.out.print(2,"registering the scoring item <"+scoring.getSer().getGuid()+"> ...");
		serItem = scoring.getSer() ;
		// finally, add serItem with score to global list, update GuiUpdater if necessary
		// choose position according to rank
		
		// over there, the results will be prepared regarding their content...
		// if done, it will be sent to the gui updater for the panels, which cares for the
		// display stuff
		// we transfer / consolidate the necessary data into a specialized object:
		// ScoredSerDocument as ietm of ScoredSerDocuments
		int n = parent.getScoredSerDocuments().introduceSerItem( serItem ) ;// .add( this );
		// this queue is then digested by the class ScoredSerDocuments::ListService <<<<<<<<<<<<<<<<<<<<<
		
		iPos=0; 
		parent.getGlobalSearchEngineResults().getItems().add( iPos, new SearchEngineResultItem(serItem) );

		
	}
	
	private boolean checkScoredItemsForUrl( ScoredSerDocuments scoredSerDocs, String urlStr) {
		boolean rB=false;
		
		for (int i=0;i<scoredSerDocs.size();i++){
			ScoredSerDocument scdoc = scoredSerDocs.get(i);
			String scdUrl = scdoc.getDocUrl() ;
			
			if (scdUrl.contentEquals(urlStr)){
				rB=true;
				break;
			}
			
		}
		
		if (rB==false){
			
			
			boolean excluded=false;
			if (parent.modelController==null){
				parent.modelController = parent.appCommons.getModelController() ;
			}
			excluded = parent.modelController.urlIsExcluded(urlStr ); 
			
		}
		
		return rB;
	}
	
	
}



// updated by PageLoader
class SearchEngineResultsImporter implements Observer{

	SessionManager parent;
	
	public SearchEngineResultsImporter(SessionManager smgr){
		parent = smgr ;
	}
	
	@Override
	public void update(Observable sender, Object dataobj) {
		/*
		 * this gets updated by the PageLoader, sub-class SeResultsDigester
		 */
		parent.out.setPrefix("[iTexx-Gui]");
		PageLoader pl ; // just for dev jumping
											parent.out.print(2, "...SessionManager received an update as observer of "+sender.toString()+", receiving data of format "+dataobj.toString());
		
		
		if (dataobj instanceof SearchEngineResults){
			// if we get the whole package, fork into object ... 
			new ImporterHelper( parent, (SearchEngineResults)dataobj );
			// this will add the incoming SER item to the list "parent.seCompletedResultsItemsBuffer"
		}
		if (dataobj instanceof SearchEngineResultItem){
			SearchEngineResultItem ser = (SearchEngineResultItem)dataobj ;
			parent.seCompletedResultsItemsBuffer.add(ser) ;
											parent.out.print(2, "Smgr got content of site : "+ ser.getTargetDocUrl());
		}
		
		
	}

	
}

class ImporterHelper{

	SessionManager parent;
	
	public ImporterHelper(SessionManager parent, SearchEngineResults serItem) {
		//
		this.parent = parent;
		go(serItem) ;
	}

	
	private void go(SearchEngineResults serItems){
		
		for (int i=0;i<serItems.size();i++){
			SearchEngineResultItem ser = serItems.get(i);
			parent.seCompletedResultsItemsBuffer.add(ser) ;
		}
		

	}
	
}